package com.wdf.rule.drools;


import cn.hutool.core.util.URLUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 规则相关动态类加载器
 *
 * @author wangdingfu
 * @date 2023-11-18 16:29:48
 */
@Slf4j
public class FuRuleDynamicClassLoader extends ClassLoader {

    public static final FuRuleDynamicClassLoader INSTANCE = new FuRuleDynamicClassLoader();

    /**
     * class字节流缓存
     */
    private final Map<String, byte[]> classCacheMap = new ConcurrentHashMap<>();

    /**
     * class路径缓存
     */
    private final Map<String, File> classFileMap = new ConcurrentHashMap<>();


    /**
     * 缓存class
     *
     * @param classPkg class的包路径
     * @param file     class文件
     */
    public void storeClass(String classPkg, File file) {
        try {
            classFileMap.put(classPkg.replace('.', File.separatorChar) + ".class", file);
            classCacheMap.put(classPkg, IOUtils.toByteArray(URLUtil.getURL(file)));
        } catch (IOException e) {
            log.error("加载文件【" + file.getPath() + "】异常:" + e.getMessage());
        }
    }


    /**
     * 读取class
     *
     * @param name The resource name
     * @return class的路径
     */
    @Override
    protected URL findResource(String name) {
        if (classFileMap.containsKey(name)) {
            File file = classFileMap.get(name);
            if (Objects.nonNull(file)) {
                return URLUtil.getURL(file);
            }
        }
        return super.findResource(name);
    }


    /**
     * 根据类名称获取类
     *
     * @param className The <a href="#binary-name">binary name</a> of the class
     * @return class对象
     */
    @Override
    protected Class<?> findClass(String className) throws ClassNotFoundException {
        if (classCacheMap.containsKey(className)) {
            byte[] byteCode = classCacheMap.get(className);
            return defineClass(className, byteCode, 0, byteCode.length);
        } else {
            return super.findClass(className);
        }
    }
}
